﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace PatcherYRpp
{
    [StructLayout(LayoutKind.Explicit, Size = 172)]
    public struct ObjectClass
    {
        public unsafe Pointer<CoordStruct> GetFLH(ref CoordStruct dest, int idxWeapon, CoordStruct baseCoords)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, ref CoordStruct, int, CoordStruct, IntPtr>)
                this.GetVirtualFunctionPointer(44);
            return func(ref this, ref dest, idxWeapon, baseCoords);
        }

        public unsafe bool Remove()
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, Bool>)Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 53);
            return func(ref this);
        }
        public unsafe bool Put(CoordStruct coord, Direction faceDir)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, ref CoordStruct, Direction, Bool>)Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 54);
            return func(ref this, ref coord, faceDir);
        }

        public unsafe bool SpawnParachuted(CoordStruct where)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, ref CoordStruct, Bool>)
                Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 58);
            return func(ref this, ref where);
        }

        public unsafe void ClickedAction(Action action, Pointer<ObjectClass> target, Bool bUnk)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, Action, IntPtr, Bool,void>)Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 81);
            func(ref this,action, target, bUnk);
        }

        public unsafe RadioCommand ReceiveCommand(Pointer<TechnoClass> pSender, RadioCommand command, AbstractClass pInOut)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, IntPtr, RadioCommand, ref AbstractClass, RadioCommand>)Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 101);
            return func(ref this, pSender, command,ref pInOut);
        }

        public unsafe void SetLocation(CoordStruct coord)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, ref CoordStruct, void>)Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 109);
            func(ref this, ref coord);
        }

        public unsafe void MarkAllOccupationBits(CoordStruct coords)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass,ref CoordStruct, void>)
               Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 60);
            func(ref this,ref coords);
        }
        public unsafe void UnmarkAllOccupationBits(CoordStruct coords)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, ref CoordStruct, void>)
               Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 61);
            func(ref this, ref coords);
        }


        public unsafe bool UnInit()
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, bool>)
                Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 62);
            return func(ref this);
        }

        public unsafe int KickOutUnit(Pointer<TechnoClass> pTechno, CellStruct cell)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, IntPtr, CellStruct, int>)
                Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 64);
            return func(ref this, pTechno, cell);
        }

        public unsafe bool UpdatePlacement(PlacementType type)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, PlacementType, Bool>)
                this.GetVirtualFunctionPointer(73);
            return func(ref this, type);
        }

        public unsafe DamageState TakeDamage(int damage, Pointer<WarheadTypeClass> pWH, bool crewed)
        {
            return TakeDamage(damage, pWH, IntPtr.Zero, IntPtr.Zero, crewed);
        }

        public unsafe DamageState TakeDamage(int damage, Pointer<WarheadTypeClass> pWH, Pointer<ObjectClass> pAttacker, Pointer<HouseClass> pAttackingHouse, bool crewed)
        {
            return ReceiveDamage(damage, 0, pWH, pAttacker, true, !crewed, pAttackingHouse);
        }



        public unsafe DamageState ReceiveDamage(int damage, int distanceFromEpicenter, Pointer<WarheadTypeClass> pWH,
            Pointer<ObjectClass> pAttacker, bool ignoreDefenses, bool preventPassengerEscape, Pointer<HouseClass> pAttackingHouse)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, IntPtr, int, IntPtr, IntPtr, Bool, Bool, IntPtr, DamageState>)
                this.GetVirtualFunctionPointer(91);
            return func(ref this, Pointer<int>.AsPointer(ref damage), distanceFromEpicenter, pWH, pAttacker, ignoreDefenses, preventPassengerEscape, pAttackingHouse);
        }

        public unsafe void Destroy()
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, void>)
                this.GetVirtualFunctionPointer(92);
            func(ref this);
        }
        public unsafe bool CanBeSelected()
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, Bool>)
                this.GetVirtualFunctionPointer(78);
            return func(ref this);
        }

        public unsafe bool CanBeSelectedNow()
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, Bool>)
                this.GetVirtualFunctionPointer(79);
            return func(ref this);
        }

        public unsafe void Select()
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, void>)
                this.GetVirtualFunctionPointer(83);
            func(ref this);
        }

        public unsafe void Deselect()
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, void>)
                this.GetVirtualFunctionPointer(84);
            func(ref this);
        }



        public unsafe int GetHeight()
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, int>)Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 114);
            return func(ref this);
        }


        public unsafe Mission GetCurrentMission()
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, Mission>)
                Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 97);
            return func(ref this);
        }

        public unsafe void RestoreMission(Mission mission)
        {
            var func = (delegate* unmanaged[Thiscall]<ref ObjectClass, Mission, void>)
                Helpers.GetVirtualFunctionPointer(Pointer<ObjectClass>.AsPointer(ref this), 98);
            func(ref this, mission);
        }

        public CoordStruct GetFLH(int idxWeapon, CoordStruct baseCoords)
        {
            CoordStruct pos = new CoordStruct();
            GetFLH(ref pos, idxWeapon, baseCoords);
            return pos;
        }



        [FieldOffset(0)]
        public AbstractClass Base;

        [FieldOffset(44)] public int FallRate; //how fast is it falling down? only works if FallingDown is set below, and actually positive numbers will move the thing UPWARDS
        [FieldOffset(48)] private IntPtr nextObject;    //Next Object in the same cell or transport. This is a linked list of Objects.
        public Pointer<ObjectClass> NextObject { get => nextObject; set => nextObject = value; }

        [FieldOffset(100)] public int CustomSound;
        [FieldOffset(104)] public Bool BombVisible; // In range of player's bomb seeing units, so should draw it

        [FieldOffset(108)] public int Health;     //The current Health.
        [FieldOffset(112)] public int EstimatedHealth; // used for auto-targeting threat estimation
        [FieldOffset(116)] public Bool IsOnMap; // has this object been placed on the map?

        [FieldOffset(128)] public Bool NeedsRedraw;
        [FieldOffset(129)] public Bool InLimbo; // act as if it doesn't exist - e.g., post mortem state before being deleted
        [FieldOffset(130)] public Bool InOpenToppedTransport;
        [FieldOffset(131)] public Bool IsSelected;    //Has the player selected this Object?
        [FieldOffset(132)] public Bool HasParachute;  //Is this Object parachuting?

        [FieldOffset(136)] private IntPtr parachute;       //Current parachute Anim.
        public Pointer<AnimClass> Parachute { get => parachute; set => parachute = value; }
        [FieldOffset(140)] public Bool OnBridge;
        [FieldOffset(141)] public Bool IsFallingDown;
        [FieldOffset(142)] public Bool WasFallingDown; // last falling state when FootClass::Update executed. used to find out whether it changed.
        [FieldOffset(143)] public Bool IsABomb; // if set, will explode after FallingDown brings it to contact with the ground
        [FieldOffset(144)] public Bool IsAlive;       //Self-explanatory.

        [FieldOffset(148)] public Layer LastLayer;
        [FieldOffset(152)] public Bool IsInLogic; // has this object been added to the logic collection?
        [FieldOffset(153)] public Bool IsVisible; // was this object in viewport when drawn?

        [FieldOffset(156)] public CoordStruct Location; //Absolute current 3D location (in leptons)
    }
}
